#include "precomp.h"

static lua_State* L;

void lua_stacktrace(lua_State* L)
{
    lua_Debug entry;
    int depth = 0; 
	Tmpl::Log::Write("");
	Tmpl::Log::Write("----- Callstack Dump ------");
	Tmpl::Log::Write("");
	while (lua_getstack(L, depth, &entry))
	{
        int status = lua_getinfo(L, "Sln", &entry);
		Tmpl::Log::Print("%s(%d): %s\n", entry.short_src, entry.currentline, entry.name ? entry.name : "?");
        depth++;
    }
	Tmpl::Log::Write("---------------------------");
	Tmpl::Log::Write("");
}

static int LuaPrintString(lua_State *L) 
{
	/* get number of arguments */
	int n = lua_gettop(L);

	/* loop through each argument */
	char txt[8192]; txt[0] = 0;
	for (int i = 1; i <= n; i++)
	{
		/* Error checking */
		if (!lua_isstring(L, i))
		{
			lua_pushstring(L, "Incorrect argument to 'print'");
			lua_error(L);
		}
		else if (i > 1)
		{
			printf("%s\t%s",txt, lua_tostring(L, i));
		}
		else
		{
			printf("%s",lua_tostring(L, i));
		}
	}
	Tmpl::Log::Write(txt);

	/* no returns */
	return 0;
}

void LuaWrapper::Init()
{
	Tmpl::Log::Write("LuaWrapper: Starting Lua");

	// Start Lua
	L = lua_open();
	luaL_openlibs(L);

	// So we can use the stacktrace func
	volatile bool x = false;
	if (x) lua_stacktrace(NULL);

	// So that we can use print string
	LuaWrapper::RegisterFunction("print", LuaPrintString);
}
void LuaWrapper::Exit()
{
	Tmpl::Log::Write("LuaWrapper: Exiting Lua");

	lua_close(L);
}

lua_State* LuaWrapper::GetLuaState()
{
	return L;
}

void LuaWrapper::RegisterFunction(const char* funcName, int(*func)(lua_State*))
{
	lua_register(L, funcName, func);
}

int LuaWrapper::LoadFile(const char* file)
{
    if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) 
    {
		int n = lua_gettop(L);
		Tmpl::Log::Print("Error loading file %s: %s\n", file, lua_tostring(L, -1));
		return -1;
	}
	return 0;
}

int LuaWrapper::ExecuteFile(const char* file)
{
    if (luaL_dofile(L, file)) 
    {
		int n = lua_gettop(L);
		Tmpl::Log::Print("Error executing file %s: %s\n", file, lua_tostring(L, -1));
		return -1;
	}
	return 0;
}
int LuaWrapper::ExecuteLuaFunction(const char* function)
{
	// Get the function
    lua_getglobal(L, function);
    if(!lua_isfunction(L,-1))
    {
        lua_pop(L,1);
		Tmpl::Log::Print("Error running function %s, not a valid function!\n", function);
        return -2;
    }

    // do the call (x arguments, x results)
    if (lua_pcall(L, 0, 0, 0) != 0) {
        Tmpl::Log::Print("Error running function %s: %s\n",function, lua_tostring(L, -1));
        return -1;
    }

	return 0;
}

const char* LuaWrapper::LuaTableGetString(const char* name, int idx)
{
	lua_pushstring(L, name);
	lua_gettable(L, idx);   // This pops "name", gets the value of "name" in the table and pushes the value
    if(!lua_isstring(L,-1))
	{
		//Tmpl::Log::Print("Error in LuaTableGetString, name = %s: %s\n", name, lua_tostring(L, -1));
		lua_pop(L, 1);
		return "";
	}
	const char* value = lua_tostring(L, -1);   // Get the returned value off the stack
	lua_pop(L, 1);   // Pops that value off the stack (returning stack to its original state)
	return value;
}
double LuaWrapper::LuaTableGetNumber(const char* name, int idx)
{
	lua_pushstring(L, name);
	lua_gettable(L, idx);   // This pops "name", gets the value of "name" in the table and pushes the value
    if(!lua_isnumber(L,-1))
	{
		//Tmpl::Log::Print("Error in LuaTableGetNumber, name = %s: %s\n", name, lua_tostring(L, -1));
		lua_pop(L, 1);
		return 0;
	}
	double number = lua_tonumber(L, -1);   // Get the returned value off the stack
	lua_pop(L, 1);   // Pops that value off the stack (returning stack to its original state)
	return number;
}
